#ifndef SHAREDMEM2_H_
#define SHAREDMEM2_H_

#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include "Object.h"
#include "Exception.h"


template <class T>

class SharedMemory2: public Object
{
static const char DEFAULT_LETTER='a';
private:

	int 	m_sharedMemId;
	T*		m_data;
	int 	m_Size;

	int attachedProcessAmmount ();

public:

	/**
	 *
	 */
	SharedMemory2 (std::string archivo,char letra=DEFAULT_LETTER ,unsigned int size =1);

	/**
	 *
	 */
	~SharedMemory2 ();

	/**
	 *
	 */
	void release ();

	/**
	 *
	 */
	void write ( T data , int pos=0);

	/**
	 *
	 */
	T read (int pos=0);

};

template <class T>
SharedMemory2<T> :: SharedMemory2 (std::string archivo,char letra, unsigned int size):
	m_Size(size),
	m_data(NULL)
{
	std::string touchCmd = "touch "+archivo;
	system(touchCmd.c_str());

	// generacion de la clave
	key_t key = ftok ( archivo.data(),letra );

	if ( key == -1 )
		throw Exception("Error while creating the key for the shared memory file:"+archivo);
	else
	{
		// creacion de la memoria compartida
		this->m_sharedMemId = shmget ( key,sizeof(T)*m_Size,0666|IPC_CREAT );

		if ( this->m_sharedMemId == -1 )
			throw Exception("Error while creating the shared memory");
		else
        {
			// attach del bloque de memoria al espacio de direcciones del proceso
			void* tempData = shmat ( this->m_sharedMemId,NULL,0 );

			if ( tempData == (void *) -1 )
				throw Exception("Error while attaching the shared memory");
			else
				this->m_data = (T *) tempData;
		}
	}
}

template <class T>
SharedMemory2<T> :: ~SharedMemory2 ()
{
}

template <class T>
void SharedMemory2<T> :: release ()
{
	// detach del bloque de memoria
	if(shmdt ( (void *) this->m_data )<0)
		throw Exception("Error while deataching the shared memory");

	int procAdosados = this->attachedProcessAmmount ();

	if ( procAdosados == 0 )
	{
		if(shmctl ( this->m_sharedMemId,IPC_RMID,NULL )<0)
			throw Exception("Error while releasing the shared memory");
	}

}

template <class T>
void SharedMemory2<T> :: write ( T data, int pos)
{
	if(m_data == NULL)
		throw Exception("Shared memory was not initalized");

	this->m_data[pos] = data;
}

template <class T>
T SharedMemory2<T> :: read (int pos)
{
	return this->m_data[pos];
}

template <class T>
int SharedMemory2<T> :: attachedProcessAmmount ()
{
	shmid_ds status;
	if(shmctl ( this->m_sharedMemId,IPC_STAT,&status )<0)
		throw Exception("Error whilw getting the attached processes");

	return status.shm_nattch;
}

#endif // SHAREDMEM2_H_
